home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / minix / libsrc~1.z / libsrc~1 / scanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-12-28  |  7.5 KB  |  416 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4.     
  5.     /*
  6.      * %efg were loosing big time
  7.      *    fixed  ++jrb
  8.      * all floating conversion now done by atof. much is gained by this.
  9.      *    ++jrb
  10.      */
  11.     
  12. #ifndef __NO_FLOAT__
  13. #define FLOATS 1
  14. #endif
  15.     
  16. #ifndef TRUE
  17. #define TRUE  1
  18. #define FALSE 0
  19. #endif
  20.     
  21. static char    _numstr[] = "0123456789ABCDEF";
  22.  
  23.  
  24. #define    skip()    while(isspace(c)) { if ((c=(*get)(ip))<1) goto done; }
  25. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  26.  
  27. #if FLOATS
  28. /* fp scan actions */
  29. #define F_NADA    0    /* just change state */
  30. #define F_SIGN    1    /* set sign */
  31. #define F_ESIGN    2    /* set exponent's sign */
  32. #define F_INT    3    /* adjust integer part */
  33. #define F_FRAC    4    /* adjust fraction part */
  34. #define F_EXP    5    /* adjust exponent part */
  35. #define F_QUIT    6
  36.  
  37. #define NSTATE    8
  38. #define FS_INIT        0    /* initial state */
  39. #define FS_SIGNED    1    /* saw sign */
  40. #define FS_DIGS        2    /* saw digits, no . */
  41. #define FS_DOT        3    /* saw ., no digits */
  42. #define FS_DD        4    /* saw digits and . */
  43. #define FS_E        5    /* saw 'e' */
  44. #define FS_ESIGN    6    /* saw exp's sign */
  45. #define FS_EDIGS    7    /* saw exp's digits */
  46.  
  47. #define FC_DIG        0
  48. #define FC_DOT        1
  49. #define FC_E        2
  50. #define FC_SIGN        3
  51.  
  52. /* given transition,state do what action? */
  53. int fp_do[][NSTATE] = {
  54.     {F_INT,F_INT,F_INT,
  55.      F_FRAC,F_FRAC,
  56.      F_EXP,F_EXP,F_EXP},    /* see digit */
  57.     {F_NADA,F_NADA,F_NADA,
  58.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  59.     {F_QUIT,F_QUIT,
  60.      F_NADA,F_QUIT,F_NADA,
  61.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  62.     {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  63.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  64. };
  65. /* given transition,state what is new state? */
  66. int fp_ns[][NSTATE] = {
  67.     {FS_DIGS,FS_DIGS,FS_DIGS,
  68.      FS_DD,FS_DD,
  69.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  70.     {FS_DOT,FS_DOT,FS_DD},    /* see '.' */
  71.     {0,0,FS_E,0,FS_E },    /* see e/E */
  72.     {FS_SIGNED,0,0,0,0,FS_ESIGN,0,0},    /* see sign */
  73. };
  74. /* which states are valid terminators? */
  75. int fp_sval[NSTATE] = {
  76.     0,0,1,0,1,0,0,1
  77. };
  78. #endif
  79.  
  80. int _scanf(ip, get, unget, fmt, args)
  81. register unsigned char *ip;
  82. int (*get)();
  83. int (*unget)();
  84. register unsigned char *fmt;
  85. char **args;
  86.  
  87. {
  88.     register long n;
  89.     register int c, width, lval, cnt = 0;
  90.     int store, neg, base, wide1, endnull, rngflag, c2;
  91.     register unsigned char *p;
  92.     unsigned char delim[128], digits[17], *q;
  93.     char *strchr(), *strcpy();
  94. #if FLOATS
  95.     double fx;
  96.     char fbuf[128], *fbp;
  97.     int fstate, trans;
  98.     extern double atof();
  99. #endif
  100.     
  101.     if (!*fmt)
  102.     return(0);
  103.     
  104.     c = (*get)(ip);
  105.     while(c > 0)
  106.     {
  107.     store = FALSE;
  108.     if (*fmt == '%')
  109.     {
  110.         n    = 0;
  111.         width    = -1;
  112.         wide1    = 1;
  113.         base    = 10;
  114.         lval    = FALSE;
  115.         store    = TRUE;
  116.         endnull    = TRUE;
  117.         neg    = -1;
  118.         
  119.         strcpy(delim,  "\011\012\013\014\015 ");
  120.         strcpy(digits, _numstr); /* "01234567890ABCDEF" */
  121.         
  122.         if (fmt[1] == '*')
  123.         {
  124.         endnull = store = FALSE;
  125.         ++fmt;
  126.         }
  127.         
  128.         while (isdigit(*++fmt))        /* width digit(s) */
  129.         {
  130.         if (width == -1)
  131.             width = 0;
  132.         wide1 = width = TEN_MUL(width) + (*fmt - '0');
  133.         }
  134.         --fmt;
  135.       fmtnxt:
  136.         ++fmt;
  137.         switch(tolower(*fmt))    /* tolower() is a MACRO! */
  138.         {
  139.           case '*':
  140.         endnull = store = FALSE;
  141.         goto fmtnxt;
  142.         
  143.           case 'l':    /* long data */
  144.         lval = TRUE;
  145.           case 'h':    /* short data (for compatibility) */
  146.         goto fmtnxt;
  147.         
  148.           case 'i':    /* any-base numeric */
  149.         base = 0;
  150.         goto numfmt;
  151.         
  152.           case 'b':    /* unsigned binary */
  153.         base = 2;
  154.         goto numfmt;
  155.         
  156.           case 'o':    /* unsigned octal */
  157.         base = 8;
  158.         goto numfmt;
  159.         
  160.           case 'x':    /* unsigned hexadecimal */
  161.         base = 16;
  162.         goto numfmt;
  163.         
  164.           case 'd':    /* SIGNED decimal */
  165.         neg = FALSE;
  166.         /* FALL-THRU */
  167.         
  168.           case 'u':    /* unsigned decimal */
  169.           numfmt:                    skip();
  170.         
  171.         if (isupper(*fmt))
  172.             lval = TRUE;
  173.         
  174.         if (!base)
  175.         {
  176.             base = 10;
  177.             neg = FALSE;
  178.             if (c == '%')
  179.             {
  180.             base = 2;
  181.             goto skip1;
  182.             }
  183.             else if (c == '0')
  184.             {
  185.             c = (*get)(ip);
  186.             if (c < 1)
  187.                 goto savnum;
  188.             if ((c != 'x')
  189.                 && (c != 'X'))
  190.             {
  191.                 base = 8;
  192.                 digits[8]= '\0';
  193.                 goto zeroin;
  194.             }
  195.             base = 16;
  196.             goto skip1;
  197.             }
  198.         }
  199.         
  200.         if ((neg == FALSE) && (base == 10)
  201.             && ((neg = (c == '-')) || (c == '+')))
  202.         {
  203.           skip1:
  204.             c = (*get)(ip);
  205.             if (c < 1)
  206.             goto done;
  207.         }
  208.         
  209.         digits[base] = '\0';
  210.         p = ((unsigned char *)
  211.              strchr(digits,toupper(c)));
  212.         
  213.         if ((!c || !p) && width)
  214.             goto done;
  215.         
  216.         while (p && width-- && c)
  217.         {
  218.             n = (n * base) + (p - digits);
  219.             c = (*get)(ip);
  220.           zeroin:
  221.             p = ((unsigned char *)
  222.              strchr(digits,toupper(c)));
  223.         }
  224.           savnum:
  225.         if (store)
  226.         {
  227.             p = ((unsigned char *) *args);
  228.             if (neg == TRUE)
  229.             n = -n;
  230.             if (lval)
  231.             *((long*) p) = n;
  232.             else
  233.             *((int *) p) = n;
  234.             ++cnt;
  235.         }
  236.         break;
  237.         
  238. #if FLOATS
  239.           case 'e':    /* float */
  240.           case 'f':
  241.           case 'g':
  242.         skip();
  243.         
  244.         if (isupper(*fmt))
  245.             lval = TRUE;
  246.         
  247.         fstate = FS_INIT;
  248.         fbp = fbuf;
  249.         while (c && width--) {
  250.             if (c >= '0' && c <= '9')
  251.             trans = FC_DIG;
  252.             else if (c == '.')
  253.             trans = FC_DOT;
  254.             else if (c == '+' || c == '-')
  255.             trans = FC_SIGN;
  256.             else if (tolower(c) == 'e')
  257.             trans = FC_E;
  258.             else
  259.             goto fdone;
  260.             
  261.             *fbp++ = c;
  262.             
  263.             if (fp_do[trans][fstate] == F_QUIT)
  264.             goto fdone;
  265.             fstate = fp_ns[trans][fstate];
  266.             c = (*get)(ip);
  267.         }
  268.         
  269.           fdone:
  270.         *fbp = '\0';
  271.         if (!fp_sval[fstate])
  272.             goto done;
  273.         if (store) {
  274.             fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
  275.             p = (unsigned char *) *args;
  276.             if (lval)
  277.             *((double *) p) = fx;
  278.             else
  279.             *((float *) p) = (float)fx;
  280.             ++cnt;
  281.         }
  282.         break;
  283. #endif
  284.         
  285.           case 'c':    /* character data */
  286.         width = wide1;
  287.         endnull    = FALSE;
  288.         delim[0] = '\0';
  289.         goto strproc;
  290.         
  291.           case '[':    /* string w/ delimiter set */
  292.         
  293.         /* get delimiters */
  294.         p = delim;
  295.         
  296.         if (*++fmt == '^')
  297.             fmt++;
  298.         else
  299.             lval = TRUE;
  300.         
  301.         rngflag = 2;
  302.         if ((*fmt == ']') || (*fmt == '-'))
  303.         {
  304.             *p++ = *fmt++;
  305.             rngflag = FALSE;
  306.         }
  307.         
  308.         while (*fmt != ']')
  309.         {
  310.             if (*fmt == '\0')
  311.             goto done;
  312.             switch (rngflag)
  313.             {
  314.               case TRUE:
  315.             c2 = *(p-2);
  316.             if (c2 <= *fmt)
  317.             {
  318.                 p -= 2;
  319.                 while (c2 < *fmt)
  320.                 *p++ = c2++;
  321.                 rngflag = 2;
  322.                 break;
  323.             }
  324.             /* fall thru intentional */
  325.             
  326.               case FALSE:
  327.             rngflag = (*fmt == '-');
  328.             break;
  329.             
  330.               case 2:
  331.             rngflag = FALSE;
  332.             }
  333.             
  334.             *p++ = *fmt++;
  335.         }
  336.         
  337.         *p = '\0';
  338.         goto strproc;
  339.         
  340.           case 's':    /* string data */
  341.         skip();
  342.           strproc:
  343.         /* process string */
  344.         p = ((unsigned char *) *args);
  345.         
  346.         /* if the 1st char fails, match fails */
  347.         if (width)
  348.         {
  349.             q = ((unsigned char *)
  350.              strchr(delim, c));
  351.             if((c < 1)
  352.                || (lval ? !q : (int) q))
  353.             {
  354.             if (endnull)
  355.                 *p = '\0';
  356.             goto done;
  357.             }
  358.         }
  359.         
  360.         for (;;) /* FOREVER */
  361.         {
  362.             if (store)
  363.             *p++ = c;
  364.             if (((c = (*get)(ip)) < 1) ||
  365.             (--width == 0))
  366.             break;
  367.             
  368.             q = ((unsigned char *)
  369.              strchr(delim, c));
  370.             if (lval ? !q : (int) q)
  371.             break;
  372.         }
  373.         
  374.         if (store)
  375.         {
  376.             if (endnull)
  377.             *p = '\0';
  378.             ++cnt;
  379.         }
  380.         break;
  381.         
  382.           case '\0':    /* early EOS */
  383.         --fmt;
  384.         /* FALL THRU */
  385.         
  386.           default:
  387.         goto cmatch;
  388.         }
  389.     }
  390.     else if (isspace(*fmt))        /* skip whitespace */
  391.     {
  392.         skip();
  393.     }
  394.     else 
  395.     {            /* normal match char */
  396.       cmatch:
  397.         if (c != *fmt) 
  398.         break;
  399.         c = (*get)(ip);
  400.     }
  401.     
  402.     if (store)
  403.         args++;
  404.     
  405.     if (!*++fmt)
  406.         break;
  407.     }
  408.     
  409.   done:                        /* end of scan */
  410.     if ((c < 0) && (cnt == 0))
  411.     return(EOF);
  412.     
  413.     (*unget)(c, ip);
  414.     return(cnt);
  415. }
  416.